package com.friend.chat.webrtc;

/**
 * @author batie fancy
 * @des
 * @date 2023/4/6
 */

import android.content.Context;
import android.view.View;

import androidx.annotation.NonNull;

import com.friend.chat.webrtc.renderer.ProxyVideoSink;

import org.webrtc.AudioSource;
import org.webrtc.AudioTrack;
import org.webrtc.Camera1Enumerator;
import org.webrtc.Camera2Enumerator;
import org.webrtc.CameraEnumerator;
import org.webrtc.DefaultVideoDecoderFactory;
import org.webrtc.DefaultVideoEncoderFactory;
import org.webrtc.EglBase;
import org.webrtc.IceCandidate;
import org.webrtc.MediaConstraints;
import org.webrtc.MediaStream;
import org.webrtc.PeerConnection;
import org.webrtc.PeerConnectionFactory;
import org.webrtc.RendererCommon;
import org.webrtc.SessionDescription;
import org.webrtc.SurfaceTextureHelper;
import org.webrtc.SurfaceViewRenderer;
import org.webrtc.VideoCapturer;
import org.webrtc.VideoDecoderFactory;
import org.webrtc.VideoEncoderFactory;
import org.webrtc.VideoSource;
import org.webrtc.VideoTrack;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;

/**
 * WebRtc 引擎类
 */
public class WebRtcEngine implements IEngine {
    private IWebRtcCallback mCallback;
    private Context mContext;
    private EglBase mEglBase;
    private PeerConnectionFactory mPeerConnectionFactory;

    private MediaStream mLocalStream;
    private VideoSource mVideoSource;
    private AudioSource mAudioSource;
    private AudioTrack mAudioTrack;
    private VideoCapturer mVideoCapture;
    private SurfaceTextureHelper mSurfaceTextureHelper;
    private SurfaceViewRenderer mSurfaceViewRenderer;
    private SurfaceViewRenderer mLocalRenderer;

    // 对话实例列表
    private ConcurrentHashMap<String, PeerManager> peers = new ConcurrentHashMap<>();

    public boolean mIsAudioOnly;


    private static final String VIDEO_TRACK_ID = "ARDAMSv0";
    private static final String AUDIO_TRACK_ID = "ARDAMSa0";


    private List<PeerConnection.IceServer> mIceServers = new ArrayList<>();

    private static final int FPS = 20;
    private static final int VIDEO_WIDTH = 640;
    private static final int VIDEO_HEIGHT = 480;

    private WebRtcEngine() {

    }

    public WebRtcEngine(Context context, boolean isAudioOnly, @NonNull IWebRtcCallback callback) {
        mContext = context;
        mIsAudioOnly = isAudioOnly;
        mCallback = callback;
        //初始化ICE服务器
        initIceServer();
        //创建上下文
        if (mEglBase == null) {
            mEglBase = EglBase.create();
        }
        //创建PeerConnectionFactory
        if (mPeerConnectionFactory == null) {
            mPeerConnectionFactory = createFactory();
        }
        if (mLocalStream == null) {
            createLocalStream();
        }
    }

    @Override
    public void init() {


    }


    private PeerConnectionFactory createFactory() {
        //1.初始化前，必须调用
        PeerConnectionFactory.initialize(PeerConnectionFactory.InitializationOptions.builder(mContext).createInitializationOptions());
        //2.可能有十个参数，许多都有默认，设置视频的编解码
        final VideoEncoderFactory videoEncoderFactory = new DefaultVideoEncoderFactory(mEglBase.getEglBaseContext(), true, true);
        final VideoDecoderFactory videoDecoderFactory = new DefaultVideoDecoderFactory(mEglBase.getEglBaseContext());
        PeerConnectionFactory.Options options = new PeerConnectionFactory.Options();
        //建造
        return PeerConnectionFactory.builder().setOptions(options).setVideoEncoderFactory(videoEncoderFactory).setVideoDecoderFactory(videoDecoderFactory).createPeerConnectionFactory();
    }

    private void createLocalStream() {
        mLocalStream = mPeerConnectionFactory.createLocalMediaStream("ARDAMS");
        //获取音频源audioSource
        mAudioSource = mPeerConnectionFactory.createAudioSource(createAudioConstraints());
        mAudioTrack = mPeerConnectionFactory.createAudioTrack(AUDIO_TRACK_ID, mAudioSource);
        mLocalStream.addTrack(mAudioTrack);

        //视频源
        if (!mIsAudioOnly) {
            mVideoCapture = createVideoCapture();
            mVideoSource = mPeerConnectionFactory.createVideoSource(mVideoCapture.isScreencast());
            //画布
            mSurfaceTextureHelper = SurfaceTextureHelper.create("CaptureThread", mEglBase.getEglBaseContext());
            mVideoCapture.initialize(mSurfaceTextureHelper, mContext, mVideoSource.getCapturerObserver());
            mVideoCapture.startCapture(VIDEO_WIDTH, VIDEO_HEIGHT, FPS);
            VideoTrack videoTrack = mPeerConnectionFactory.createVideoTrack(VIDEO_TRACK_ID, mVideoSource);
            mLocalStream.addTrack(videoTrack);
        }
    }

    private VideoCapturer createVideoCapture() {
        if (Camera2Enumerator.isSupported(mContext)) {
            return createCameraCapture(new Camera2Enumerator(mContext));
        } else {
            return createCameraCapture(new Camera1Enumerator());
        }
    }

    /**
     * 创建相机媒体流
     */
    private VideoCapturer createCameraCapture(CameraEnumerator enumerator) {
        final String[] deviceNames = enumerator.getDeviceNames();
        // First, try to find front facing camera
        for (String deviceName : deviceNames) {
            if (enumerator.isFrontFacing(deviceName)) {
                VideoCapturer videoCapturer = enumerator.createCapturer(deviceName, null);
                if (videoCapturer != null) {
                    return videoCapturer;
                }
            }
        }

        // Front facing camera not found, try something else
        for (String deviceName : deviceNames) {
            if (!enumerator.isFrontFacing(deviceName)) {
                VideoCapturer videoCapturer = enumerator.createCapturer(deviceName, null);
                if (videoCapturer != null) {
                    return videoCapturer;
                }
            }
        }
        return null;
    }


    @Override
    public void joinRoom(List<String> userIds) {

    }

    @Override
    public void personIn(String ownId, String toUid) {
        PeerManager peerManager = new PeerManager(mPeerConnectionFactory, mIceServers, new IWebRtcCallback() {
            @Override
            public void sendOffer(SessionDescription sdp) {
                mCallback.sendOffer(sdp);
            }

            @Override
            public void sendAnswer(SessionDescription sdp) {
                mCallback.sendAnswer(sdp);
            }

            @Override
            public void sendIceCandidate(String sdpMid, int sdpMLineIndex, String sdp) {
                mCallback.sendIceCandidate(sdpMid, sdpMLineIndex, sdp);
            }

            @Override
            public void onRemoteStream(MediaStream stream) {
                mCallback.onRemoteStream(stream);
            }
        });
       // peerManager.setOffer(true);
        peerManager.addStream(mLocalStream);
        peers.put(ownId, peerManager);
      //  peerManager.createOffer();

    }

    public void createOffer(String ownId){
        PeerManager peerManager = peers.get(ownId);
        peerManager.setOffer(true);
        peerManager.createOffer();
    }


    @Override
    public void receiveOffer(String ownId, String description) {
        //来自信令服务器的信息
        PeerManager peerManager = peers.get(ownId);
        if (peerManager != null) {
            SessionDescription sdp = new SessionDescription(SessionDescription.Type.OFFER, description);
            //标记为接听者
            peerManager.setOffer(false);
            peerManager.setRemoteDescription(sdp);
            peerManager.createAnswer();
        }
    }

    @Override
    public void receiveAnswer(String ownId, String description) {
        //来自信令服务器的信息
        PeerManager peerManager = peers.get(ownId);
        if (peerManager != null) {
            SessionDescription sdp = new SessionDescription(SessionDescription.Type.ANSWER, description);
            peerManager.setRemoteDescription(sdp);
        }
    }

    @Override
    public void receiveIceCandidate(String ownId, String sdpMid, int sdpMLineIndex, String sdp) {
        PeerManager peerManager = peers.get(ownId);
        if (peerManager != null) {
            IceCandidate iceCandidate = new IceCandidate(sdpMid, sdpMLineIndex, sdp);
            peerManager.addRemoteIceCandidate(iceCandidate);
        }
    }

    @Override
    public View setupLocalPreview(boolean isOverlay) {
        if (mEglBase == null) {
            return null;
        }
        mLocalRenderer = new SurfaceViewRenderer(mContext);
        mLocalRenderer.init(mEglBase.getEglBaseContext(), null);
        mLocalRenderer.setScalingType(RendererCommon.ScalingType.SCALE_ASPECT_FIT);
        mLocalRenderer.setMirror(true);
        mLocalRenderer.setZOrderMediaOverlay(isOverlay);

        ProxyVideoSink localSink = new ProxyVideoSink();
        localSink.setTarget(mLocalRenderer);
        if (mLocalStream.videoTracks.size() > 0) {
            mLocalStream.videoTracks.get(0).addSink(localSink);
        }
        return mLocalRenderer;
    }

    /**
     * ICE （Interactive Connectivity Establishment) 互动式连接建立
     * 该技术可以让客户端成功穿透远程用户与网络之间可能存在的各类防火墙
     */
    private void initIceServer() {
        PeerConnection.IceServer var1 = PeerConnection.IceServer.builder("turn:116.62.149.187:3478")
                .setUsername("root")
                .setPassword("12345678").createIceServer();
        mIceServers.add(var1);
        PeerConnection.IceServer var2 = PeerConnection.IceServer.builder("turn:116.62.149.187:3478?transport=udp")
                .setUsername("root")
                .setPassword("12345678").createIceServer();
        mIceServers.add(var2);
        PeerConnection.IceServer var3 = PeerConnection.IceServer.builder("turn:116.62.149.187:3478?transport=tcp")
                .setUsername("root")
                .setPassword("12345678").createIceServer();
        mIceServers.add(var3);
        PeerConnection.IceServer var4 = PeerConnection.IceServer.builder("stun:116.62.149.187:3478?transport=udp").createIceServer();
        mIceServers.add(var4);


       /* PeerConnection.IceServer var12 = PeerConnection.IceServer.builder("turn:42.192.40.58:3478?transport=udp")
                .setUsername("ddssingsong")
                .setPassword("123456")
                .createIceServer();
        PeerConnection.IceServer var13 = PeerConnection.IceServer.builder("turn:42.192.40.58:3478?transport=tcp")
                .setUsername("ddssingsong")
                .setPassword("123456")
                .createIceServer();
        mIceServers.add(var12);
        mIceServers.add(var13);*/
    }

    /**
     * 各种约束
     */
    private static final String AUDIO_ECHO_CANCELLATION_CONSTRAINT = "googEchoCancellation";
    private static final String AUDIO_AUTO_GAIN_CONTROL_CONSTRAINT = "googAutoGainControl";
    private static final String AUDIO_HIGH_PASS_FILTER_CONSTRAINT = "googHighpassFilter";
    private static final String AUDIO_NOISE_SUPPRESSION_CONSTRAINT = "googNoiseSuppression";

    /**
     * 配置音频约束参数
     */
    private MediaConstraints createAudioConstraints() {
        MediaConstraints audioConstraints = new MediaConstraints();
        audioConstraints.mandatory.add(new MediaConstraints.KeyValuePair(AUDIO_ECHO_CANCELLATION_CONSTRAINT, "true"));
        audioConstraints.mandatory.add(new MediaConstraints.KeyValuePair(AUDIO_AUTO_GAIN_CONTROL_CONSTRAINT, "false"));
        audioConstraints.mandatory.add(new MediaConstraints.KeyValuePair(AUDIO_HIGH_PASS_FILTER_CONSTRAINT, "false"));
        audioConstraints.mandatory.add(new MediaConstraints.KeyValuePair(AUDIO_NOISE_SUPPRESSION_CONSTRAINT, "true"));
        return audioConstraints;
    }

    public EglBase.Context getEglContext() {
        return mEglBase.getEglBaseContext();
    }
}
